package com.sky.controller.admin;

import com.sky.constant.JwtClaimsConstant;
import com.sky.dto.EmployeeDTO;
import com.sky.dto.EmployeeLoginDTO;
import com.sky.dto.EmployeePageQueryDTO;
import com.sky.entity.Employee;
import com.sky.properties.JwtProperties;
import com.sky.result.PageResult;
import com.sky.result.Result;
import com.sky.service.EmployeeService;
import com.sky.utils.JwtUtil;
import com.sky.vo.EmployeeLoginVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;

/**
 * 员工管理
 */
@RestController
@RequestMapping("/admin/employee")
@Slf4j
@Api(tags = "员工相关接口")     //api用在类上，例如Controller，表示对类的说明,通过注解可以控制生成的接口文档，使接 口文档拥有更好的可读性
public class EmployeeController {

    @Autowired
    private EmployeeService employeeService;
    @Autowired
    private JwtProperties jwtProperties;

    /**
     * 登录
     *很多人稀里糊涂的，我给大家介绍一下，那个dto封装的是登陆的用户名和密码，然后employee封装的是登陆者的相关信息，最后那个之所以返回VO不返回employee是因为要封装token进去
     *
     * 员工登录成功后会生成JWT令牌并响应给前端,
     * 后续请求中，前端会携带JWT令牌，通过JWT令牌可以解析出当前登录员工id
     * @param employeeLoginDTO
     * @return
     */
    @PostMapping("/login")
    @ApiOperation(value = "员工登录")   //@ApiOperation用在方法上，例如Controller的方法，说明方法的用途、作用,通过注解可以控制生成的接口文档，使接 口文档拥有更好的可读性
    public Result<EmployeeLoginVO> login(@RequestBody EmployeeLoginDTO employeeLoginDTO) {      //前端发过来的数据如用户名和密码为json格式数据，requestbody注释，封装为dto对象
        log.info("员工登录：{}", employeeLoginDTO);

        //ctrl+alt+b可以快速进入EmployeeServiceImpl的login方法
        Employee employee = employeeService.login(employeeLoginDTO);

        //登录成功后，生成jwt令牌
        Map<String, Object> claims = new HashMap<>();
        claims.put(JwtClaimsConstant.EMP_ID, employee.getId());
        String token = JwtUtil.createJWT(
                jwtProperties.getAdminSecretKey(),
                jwtProperties.getAdminTtl(),
                claims);

//前端数据封装成DTO对象->sql返回数据封装成entity对象->返回给前端数据封装成VO对象->返回格式result对象，
        EmployeeLoginVO employeeLoginVO = EmployeeLoginVO.builder()   //调用builder方法构建对象，前提是EmployeeLoginVO加了builder注释
                .id(employee.getId())
                .userName(employee.getUsername())
                .name(employee.getName())
                .token(token)
                .build();

        return Result.success(employeeLoginVO); //把后端结果再封装到result对象里去
    }

    /**
     * 退出
     *
     * @return
     */
    @PostMapping("/logout")
    @ApiOperation("员工退出")
    public Result<String> logout() {
        return Result.success();
    }


    /**
     * 新增员工
     *
     * @param employeeDTO
     * @return
     */
    @PostMapping
    @ApiOperation("新增员工")  //接口文档的注释
    public Result save(@RequestBody EmployeeDTO employeeDTO){   //提交过来的是json格式的数据，所以要加上requestbody
        log.info("新增员工，{}",employeeDTO);  //{}是占位符，程序运行时，会把后面的参数动态的拼到占位符

        //客户端每一次发起的请求，都会对应一个单独的线程，输出当前线程的id
        System.out.println("EmployeeController的方法save，当前线程的id："+Thread.currentThread().getId());

        //ctrl+alt+b--->快捷键到EmployeeServiceImpl的save方法
        employeeService.save(employeeDTO);

        return Result.success();
    }

    /**
     * 员工分页查询
     *
     * 项目接口文档：
     * 请求方式是get，请求路径是/admin/employee/page
     * page页码,pageSize每页的记录数,是必须提交过去的参数
     * 请求参数不是json格式的，而是query查询参数：通过地址栏？这种方式来传参
     *
     * 返回数据，也就是后端响应给前端的数据格式：code,msg,data。
     * data包括total字段（总的记录数），和records字段。  而封装的pageResult有两个属性total和records刚好对应上返回的data数据
     * records表示当前这一页要展示的数据集合，因为有多个，所以是一个数组object[],因为有很多属性，所以可以用employ实体类来封装
     *
     * 员工信息分页查询后端返回的对象类型为：Result<PageResult>,
     * 然后把这个result对象转成jason格式返回给前端,而code，msg，data三个属性就来自于result，而里面的data属性又对应一个对象PageResult
     * @param employeePageQueryDTO
     * @return
     */
    @GetMapping("/page")
    @ApiOperation("员工分页查询")
    public Result<PageResult> page(EmployeePageQueryDTO employeePageQueryDTO){    //前端提交过来了请求参数，所以用一个dto封装一下,并且类型是query的，不是Jason的，所以不用@requestBody注解
        log.info("员工分页查询，参数为:{}",employeePageQueryDTO);
        PageResult pageResult = employeeService.pageQuery(employeePageQueryDTO);
        return Result.success(pageResult);    //pageResult会当做一个object对象到result.success,赋值给data
    }

    /**
     * 启用禁用员工账号
     *1). 路径参数携带状态值。
     *2). 同时，把id传递过去，明确对哪个用户进行操作。
     *3). 返回数据code状态是必须，其它是非必须。
     *
     * @param status
     * @param id
     * @return
     */
    @PostMapping("/status/{status}")
    @ApiOperation("启用禁用员工账号")
    //本案例中查询类的操作要返回data数据，所以result要加上泛型。当前不是查询类型，只要返回code就行，一般data都是空的，这时候泛型就没必要加了
    //我们这实体类中所有的id都是long型的，status是路径参数，所以要加注解PathVariable。id是通过地址栏传参，所以不用PathVariable修饰
    public Result startOrstop(@PathVariable Integer status,Long id){
        log.info("启用禁用员工账号:{},{}",status,id);   //两个占位符
        employeeService.startOrStop(status,id);
        return Result.success();
    }

    /**
     * 根据id查询员工信息
     * @param id
     * @return
     */
    @GetMapping("/{id}")    //id是通过路径参数来传过去的
    @ApiOperation("根据id查询员工信息")
    //回显员工信息包括data，data包含的信息对应employee这个实体类
    public Result<Employee> getById(@PathVariable Long id){
        log.info("根据id:{}查询回显员工信息",id);
        Employee employee = employeeService.getById(id);
        return Result.success(employee);
    }
    /**
     * 编辑员工信息
     *
     * 注:因为是修改功能，请求方式可设置为PUT。
     * @param employeeDTO
     * @return
     */
    @PutMapping
    @ApiOperation("编辑员工信息")
    //接口文档:通过请求体来提交数据,数据格式是json格式。返回数据有code是必须的（code反应程序运行成功还是失败，失败了就要编写msg信息）
    public Result update(@RequestBody EmployeeDTO employeeDTO){
        log.info("编辑员工信息:{}",employeeDTO);
        employeeService.update(employeeDTO);
        return Result.success();
    }



}
